package com.xidata.dict.translate.youdao;

import com.alibaba.fastjson.JSON;
import com.xidata.dict.model.Language;
import com.xidata.dict.model.LookupRequest;
import com.xidata.dict.service.TranslateService;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.*;

@Data
@Component
@Slf4j
public class YoudaoTranslator implements TranslateService {

    @Resource
    YoudaoConfig youdaoConfig;

    private static Logger logger = LoggerFactory.getLogger(YoudaoTranslator.class);

    public void main(String[] args) throws IOException, InvocationTargetException, IllegalAccessException, NoSuchMethodException {

        YoudaoTranslateRequest youdaoParam = new YoudaoTranslateRequest();

        youdaoParam.setQ("你好");

        String salt = String.valueOf(System.currentTimeMillis());
        String curtime = String.valueOf(System.currentTimeMillis() / 1000);
        String signStr = youdaoConfig.getAppKey() + truncate(youdaoParam.getQ()) + salt + curtime + youdaoConfig.getAppSecret();
        String sign = getDigest(signStr);

        youdaoParam.setFrom(YoudaoLanguage.EN);
        youdaoParam.setTo(YoudaoLanguage.ZH_CHS);
        youdaoParam.setSignType("v3");
        youdaoParam.setCurtime(curtime);
        youdaoParam.setAppKey(youdaoConfig.getAppKey());
        youdaoParam.setSalt(salt);
        youdaoParam.setSign(sign);
        youdaoParam.setVocabId("您的用户词表ID");

        /** 处理结果 */
        requestForHttp(youdaoConfig.url, BeanUtils.describe(youdaoParam));
    }


    @Override
    public String translate(LookupRequest request) {

        try {
            Thread.sleep(60);

            Language s = Language.valueOf(request.getSourceLanguage());
            Language t = Language.valueOf(request.getTargetLanguage());

            YoudaoLanguage ys = YoudaoLanguage.fromLanguage(s);
            YoudaoLanguage yt = YoudaoLanguage.fromLanguage(t);

            YoudaoTranslateResponse response = toTranslate(request.getText(), ys.getValue(), yt.getValue());
            if (response == null || response.getTranslation() == null || response.getTranslation().isEmpty())
                return null;
            return response.getTranslation().get(0);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
        return request.getText();
    }

    /**
     * 翻译
     *
     * @param q
     * @return
     * @throws IOException
     */
    private YoudaoTranslateResponse toTranslate(String q, String from, String to) throws IOException {
        Map<String, String> params = new HashMap<String, String>();
        String salt = String.valueOf(System.currentTimeMillis());
        params.put("from", from);
        params.put("to", to);
        params.put("signType", "v3");
        String curtime = String.valueOf(System.currentTimeMillis() / 1000);
        params.put("curtime", curtime);
        String signStr = youdaoConfig.appKey + truncate(q) + salt + curtime + youdaoConfig.appSecret;
        String sign = getDigest(signStr);
        params.put("appKey", youdaoConfig.appKey);
        params.put("q", q);
        params.put("salt", salt);
        params.put("sign", sign);
        params.put("vocabId", "您的用户词表ID");
        /** 处理结果 */
        return requestForHttp(youdaoConfig.url, params);
    }

    public static YoudaoTranslateResponse requestForHttp(String url, Map<String, String> params) throws IOException {

        /** 创建HttpClient */
        CloseableHttpClient httpClient = HttpClients.createDefault();

        /** httpPost */
        HttpPost httpPost = new HttpPost(url);
        List<NameValuePair> paramsList = new ArrayList<NameValuePair>();
        Iterator<Map.Entry<String, String>> it = params.entrySet().iterator();
        while (it.hasNext()) {
            Map.Entry<String, String> en = it.next();
            String key = en.getKey();
            String value = en.getValue();
            paramsList.add(new BasicNameValuePair(key, value));
        }
        httpPost.setEntity(new UrlEncodedFormEntity(paramsList, "UTF-8"));
        CloseableHttpResponse httpResponse = httpClient.execute(httpPost);
        try {
            Header[] contentType = httpResponse.getHeaders("Content-Type");
            if ("audio/mp3".equals(contentType[0].getValue())) {
                //如果响应是wav
                HttpEntity httpEntity = httpResponse.getEntity();
                ByteArrayOutputStream baos = new ByteArrayOutputStream();
                httpResponse.getEntity().writeTo(baos);
                byte[] result = baos.toByteArray();
                EntityUtils.consume(httpEntity);
                if (result != null) {//合成成功
                    String file = "合成的音频存储路径" + System.currentTimeMillis() + ".mp3";
                    byte2File(result, file);
                }
            } else {
                /** 响应不是音频流，直接显示结果 */
                HttpEntity httpEntity = httpResponse.getEntity();
                String json = EntityUtils.toString(httpEntity, "UTF-8");
                EntityUtils.consume(httpEntity);
                log.info(json);

                return JSON.parseObject(json, YoudaoTranslateResponse.class);
            }
        } finally {
            try {
                if (httpResponse != null) {
                    httpResponse.close();
                }
            } catch (IOException e) {
                logger.info("## release resouce error ##" + e);
            }
        }
        return null;
    }

    /**
     * 生成加密字段
     */
    public static String getDigest(String string) {
        if (string == null) {
            return null;
        }
        char hexDigits[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
        byte[] btInput = string.getBytes(StandardCharsets.UTF_8);
        try {
            MessageDigest mdInst = MessageDigest.getInstance("SHA-256");
            mdInst.update(btInput);
            byte[] md = mdInst.digest();
            int j = md.length;
            char str[] = new char[j * 2];
            int k = 0;
            for (byte byte0 : md) {
                str[k++] = hexDigits[byte0 >>> 4 & 0xf];
                str[k++] = hexDigits[byte0 & 0xf];
            }
            return new String(str);
        } catch (NoSuchAlgorithmException e) {
            return null;
        }
    }

    /**
     * @param result 音频字节流
     * @param file   存储路径
     */
    private static void byte2File(byte[] result, String file) {
        File audioFile = new File(file);
        FileOutputStream fos = null;
        try {
            fos = new FileOutputStream(audioFile);
            fos.write(result);

        } catch (Exception e) {
            logger.info(e.toString());
        } finally {
            if (fos != null) {
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

    }

    public static String truncate(String q) {
        if (q == null) {
            return null;
        }
        int len = q.length();
        String result;
        return len <= 20 ? q : (q.substring(0, 10) + len + q.substring(len - 10, len));
    }


    @Override
    public String getProviderName() {
        return "youdao";
    }
}